// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Services.Protocols;
using System.Runtime.Serialization;
using System.Globalization;
using System.Security.Permissions;

using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using System.Net;

[assembly: CLSCompliant(true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum)]

namespace Microsoft.DDSolutions.Tfs
{
    public enum RoleType { TfsRole, SPRole, RSRole };

    /// <summary>
    ///   TfsUser object to hold a given tfs user name and his associated roles 
    /// </summary>
    public class TfsUser : IEquatable<TfsUser>
    {
        private string UserName;
        private string mDisplayName;
        private Collection<string> mTfsRoles;
        private Collection<string> mSpRoles;
        private Collection<string> mRsRoles;

        public TfsUser(string tfsUserName)
        {
            UserName = tfsUserName;
            mTfsRoles = new Collection<string>();
            mSpRoles = new Collection<string>();
            mRsRoles = new Collection<string>();
        }

        /// <summary>
        ///  Implements logic to check for equality of objects of type TfsUser
        /// </summary>
        /// <param name="other">Another instance of TfsUser Object</param>
        /// <returns></returns>
        public bool Equals(TfsUser other)
        {
            bool eq;

            eq = (String.Compare(this.UserName, other.Name, true, CultureInfo.CurrentCulture) == 0);

            eq = eq && (this.TfsRoles.Count == other.TfsRoles.Count);
            eq = eq && (this.RSRoles.Count == other.RSRoles.Count);
            eq = eq && (this.SPRoles.Count == other.SPRoles.Count);

            if (eq == true)
            {
                foreach (string tfsRole in other.TfsRoles)
                    eq = eq && this.TfsRoles.Contains(tfsRole);

                foreach (string spRole in other.SPRoles)
                    eq = eq && this.SPRoles.Contains(spRole);

                foreach (string rsRole in other.RSRoles)
                    eq = eq && this.RSRoles.Contains(rsRole);
            }

            return eq;
        }

        /// <summary>
        ///  Override the default Object.Equals to use this type's Equals implementation.
        /// </summary>
        /// <param name="obj">Another instance of object</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            TfsUser tfsUser = obj as TfsUser;

            // if tfsUser is null it can never be equal to anything
            if (tfsUser == null) return false;
            return Equals(tfsUser);
        }

        public static bool operator ==(TfsUser left, TfsUser right)
        {
            //if left or right is null or even if both are null they are not equal
            if (left == null || right == null) return false;
            return left.Equals(right);
        }

        public static bool operator !=(TfsUser left, TfsUser right)
        {
            //if left or right is null or even if both are null they are not equal as null objects cannot be equal to anything
            if (left == null || right == null) return true;
            return !left.Equals(right);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return Name;
        }

        /// <summary>
        ///   Name of the TFS User 
        /// </summary>
        public string Name
        {
            get
            {
                return UserName;
            }
        }

        /// <summary>
        ///   Name of the TFS User 
        /// </summary>
        public string DisplayName
        {
            get
            {
                return mDisplayName;
            }
            set
            {
                mDisplayName = value;
            }
        }

        /// <summary>
        ///   Public method to add role.
        /// </summary>
        /// <param name="userRole">Add role of the user</param>
        /// <param name="roleType">One of RoleType enum. RoleType.TFSROLE,RoleType.SPROLE,RoleType.RSROLE</param>
        public void AddRole(string userRole, RoleType roleType)
        {
            if (userRole == null) throw new ArgumentNullException("userRole");

            if (string.IsNullOrEmpty(userRole) == true) throw new ArgumentException("Invalid userRole");

            switch (roleType)
            {
                case RoleType.TfsRole:
                    mTfsRoles.Add(userRole);
                    break;
                case RoleType.SPRole:
                    mSpRoles.Add(userRole);
                    break;
                case RoleType.RSRole:
                    mRsRoles.Add(userRole);
                    break;
                default:
                    throw new ArgumentException("Invalid Role Type");
            }
        }

        /// <summary>
        ///   Read only string collection of the user's TFS Roles.
        /// </summary>
        public ReadOnlyCollection<string> TfsRoles
        {
            get
            {
                return new ReadOnlyCollection<string>(mTfsRoles);
            }
        }

        /// <summary>
        ///  Read only string collection of the user's Share Point Roles
        /// </summary>
        public ReadOnlyCollection<string> SPRoles
        {
            get
            {
                return new ReadOnlyCollection<string>(mSpRoles);
            }
        }

        /// <summary>
        ///  Read only string collection of the user's Reporting Services Roles
        /// </summary>

        public ReadOnlyCollection<string> RSRoles
        {
            get
            {
                return new ReadOnlyCollection<string>(mRsRoles);
            }
        }
    };

    /// <summary>
    ///  Base custom exception for TFS proxy. All other TFS related custom applications shall
    /// inherit from this.
    /// </summary>
    [Serializable]
    public class TfsBaseApplicationException : Exception
    {
        private string tfsServerName;
        private string tfsProjectName = "";

        public TfsBaseApplicationException()
            : base()
        {
        }

        /// <summary>
        /// Constructor accepting a single string message
        /// </summary>
        /// <param name="message">Exception Message</param>

        public TfsBaseApplicationException(string message)
            : base(message)
        {
        }

        /// <summary>
        /// Constructor accepting a single string message and the name of the tfs server
        /// </summary>
        /// <param name="message">Exception Message</param>
        /// <param name="tfsServer">TFS Server host Name</param>

        public TfsBaseApplicationException(string message, string tfsServer)
            : base(message)
        {
            tfsServerName = tfsServer;
        }

        /// <summary>
        /// Constructor accepting a string message and an inner exception which will be wrapped by this 
        /// custom exception class
        /// </summary>
        /// <param name="message">Exception Message</param>
        /// <param name="inner">Inner Exception</param>
        public TfsBaseApplicationException(string message,
                 Exception inner)
            : base(message, inner)
        {
        }

        /// <summary>
        ///  Deserialize the tfs servername and tfs project name
        /// </summary>
        /// <param name="info">SerializedInfo object</param>
        /// <param name="context">StreamingContext</param>
        protected TfsBaseApplicationException(SerializationInfo info, StreamingContext context)
            :
                  base(info, context)
        {
            if (info == null) throw new ArgumentNullException("info");
            tfsServerName = info.GetString("tfsServerName");
            tfsProjectName = info.GetString("tfsProjectName");
        }

        /// <summary>
        ///  Serialize the tfs server name and tfs project name 
        /// </summary>
        /// <param name="info">SerializedInfo object</param>
        /// <param name="context">StreamingContext</param>
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new ArgumentNullException("info");
            info.AddValue("tfsServerName", tfsServerName, typeof(String));
            info.AddValue("tfsProjectName", tfsProjectName, typeof(String));
            base.GetObjectData(info, context);
        }

        /// <summary>
        ///  Name of the team foundation server
        /// </summary>
        public string TeamFoundationServer
        {
            get
            {
                return tfsServerName;
            }
            set
            {
                tfsServerName = value;
            }
        }

        /// <summary>
        ///  Name of the current team project 
        /// </summary>
        public string TeamProject
        {
            get
            {
                return tfsProjectName;
            }
            set
            {
                tfsProjectName = value;
            }
        }

    }


    /// <summary>
    ///    This exception is to be thrown when the TFS connection is not 
    /// yet established and the user tries to call IsUserExist function.
    /// </summary>
    [Serializable]
    public class InvalidTfsConnectionException : TfsBaseApplicationException
    {
        public InvalidTfsConnectionException()
            : base()
        {
        }

        protected InvalidTfsConnectionException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {

        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
        }
        public InvalidTfsConnectionException(string msg, string tfsServer) : base(msg, tfsServer) { }
        public InvalidTfsConnectionException(string msg) : base(msg) { }
        public InvalidTfsConnectionException(string msg, Exception inner) : base(msg, inner) { }
    };


    /// <summary>
    ///    Application level Exception for TFS Server exception
    /// </summary>
    [Serializable]
    public class InvalidTfsServerException : TfsBaseApplicationException
    {
        public InvalidTfsServerException()
            : base()
        {
        }

        protected InvalidTfsServerException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {

        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
        }
        public InvalidTfsServerException(string msg, string tfsServer) : base(msg, tfsServer) { }
        public InvalidTfsServerException(string msg) : base(msg) { }
        public InvalidTfsServerException(string msg, Exception inner) : base(msg, inner) { }
    };

    /// <summary>
    ///    Application level Exception for TFS Server Client mismatch
    /// </summary>
    [Serializable]
    public class TfsClientServerMismatchException : TfsBaseApplicationException
    {
        public TfsClientServerMismatchException()
            : base()
        {
        }

        public TfsClientServerMismatchException(string msg, string tfsServer) : base(msg, tfsServer) { }
        public TfsClientServerMismatchException(string msg) : base(msg) { }
        public TfsClientServerMismatchException(string msg, Exception inner) : base(msg, inner) { }

        protected TfsClientServerMismatchException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {

        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
        }

    };
    /// <summary>
    ///   Application level Exception for Invalid TFS User. Its Serializable as it has additional 
    /// properties like User name in addtion to fields in the ApplicationException class 
    /// that needs to be serialized.
    /// </summary>
    [Serializable]
    public class InvalidTfsUserException : TfsBaseApplicationException
    {
        private string tfsUserName;

        public InvalidTfsUserException()
            : base()
        {
        }

        public InvalidTfsUserException(string msg, string user, string tfsServer, string tfsProject)
            : base(msg, tfsServer)
        {
            tfsUserName = user;
            base.TeamProject = tfsProject;
        }
        public InvalidTfsUserException(string msg, string tfsServer) : base(msg, tfsServer) { }
        public InvalidTfsUserException(string msg) : base(msg) { }
        public InvalidTfsUserException(string msg, Exception inner) : base(msg, inner) { }

        protected InvalidTfsUserException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            if (info == null) throw new ArgumentNullException("info");
            tfsUserName = info.GetString("tfsUserName");
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new ArgumentNullException("info");
            info.AddValue("tfsUserName", tfsUserName, typeof(String));
            base.GetObjectData(info, context);
        }

        public string User
        {
            get
            {
                return tfsUserName;
            }
            set
            {
                tfsUserName = value;
            }
        }

    };

    /// <summary>
    ///   Application level Exception for Invalid TFS Role.Its Serializable as it has additional 
    /// properties like TFS Role name in addtion to fields in the ApplicationException class 
    /// that needs to be serialized.
    /// </summary>
    [Serializable]
    public class InvalidTfsRoleException : TfsBaseApplicationException
    {
        private string tfsRole;

        public InvalidTfsRoleException()
            : base()
        {
        }

        public InvalidTfsRoleException(string msg, string role, string tfsServer, string tfsProject)
            : base(msg, tfsServer)
        {
            tfsRole = role;
            base.TeamProject = tfsProject;
        }
        public InvalidTfsRoleException(string msg, string tfsServer) : base(msg, tfsServer) { }
        public InvalidTfsRoleException(string msg) : base(msg) { }
        public InvalidTfsRoleException(string msg, Exception inner) : base(msg, inner) { }

        protected InvalidTfsRoleException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            if (info == null) throw new ArgumentNullException("info");
            tfsRole = info.GetString("tfsRole");
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new ArgumentNullException("info");
            info.AddValue("tfsRole", tfsRole, typeof(String));
            base.GetObjectData(info, context);
        }

        public string Role
        {
            get
            {
                return tfsRole;
            }
            set
            {
                tfsRole = value;
            }
        }
    };

    ///<summary>
    ///  This is the proxy object to interact with Team Foundation Server.
    ///</summary>

    public class TfsServerProxy
    {
        private TeamFoundationServer tfsServer;

        // Service Interface handles
        private IGroupSecurityService tfsSecurityService;
        private ICommonStructureService tfsProjectService;
        private IRegistration tfsRegistrationService;

        private ProjectInfo[] projects;

        private Hashtable htProjectsAndUris = new Hashtable();
        private Hashtable htProjectsAndNames = new Hashtable();

        private string appTierHost;
        private string tfsDataHostName;
        private System.Uri tfsReportsServiceUrl;
        private System.Uri tfsBaseSiteUrl;
        private System.Uri tfsAdminServiceUrl;

        public TfsServerProxy()
        {

        }

        /// <summary>
        /// Indicates whether we are dealing with server-level permission (IsProjectSite=false) or project-level permission (IsProjectSite=true)
        /// </summary>
        public bool IsProjectSite
        {
            get;
            set;
        }


        /// <summary>
        ///  Added to check for client server mismatch. We need to keep it this way until they change
        /// the API to support proper version info across client versions.
        /// </summary>
        /// <param name="message">The message of the SOAP exception thrown is compared</param>
        /// <returns>true if matches to indicate that there is a mismatch</returns>
        public static bool IsServerClientMismatch(string message)
        {
            return TFSResource.TFSClientServerMismatchErrorMsg.Equals(message) == true;
        }

        /// <summary>
        ///   Gathers various services from a TeamFoundationServer instance
        /// </summary>
        /// <param name="tfsAppServer">Instance of a TeamFoundationServer that should already be fully authenticated</param>
        public void Connect(TeamFoundationServer tfsAppServer)
        {
            if (tfsAppServer == null)
            {
                throw new ArgumentNullException("tfsAppServer");
            }

            appTierHost = tfsAppServer.Name;
            tfsServer = tfsAppServer;
            tfsProjectService = (ICommonStructureService)tfsServer.GetService(typeof(ICommonStructureService));
            tfsSecurityService = (IGroupSecurityService)tfsServer.GetService(typeof(IGroupSecurityService));
            tfsRegistrationService = (IRegistration)tfsServer.GetService(typeof(IRegistration));

            GetHostNames();
        }

        /// <summary>
        ///  Get Project Names
        /// </summary>
        /// <returns>ReadOnlyCollection of project names</returns>
        public ReadOnlyCollection<string> ProjectNames
        {
            get
            {
                Collection<string> ProjectNames = new Collection<string>();

                for (int i = 0; i < projects.Length; ++i)
                {
                    ProjectNames.Add(projects[i].Name);
                }

                return new ReadOnlyCollection<string>(ProjectNames);
            }
        }

        /// <summary>
        ///  Get all the project details 
        /// </summary>
        public void GetAllProjectInfo()
        {
            projects = tfsProjectService.ListAllProjects();

            foreach (ProjectInfo project in projects)
            {
                htProjectsAndUris.Add(project.Uri, project);
                htProjectsAndNames.Add(project.Name, project);
            }
        }

        /// <summary>
        ///   Gets a collection of TFS Users along with their roles.
        /// </summary>
        /// <param name="nodeName">Name of the team project</param>
        /// <returns>Returns a collection of TFSUser structure. It has tfsUserName and associated TFS roles</returns>
        public Collection<TfsUser> GetAllUsers(string nodeName)
        {
            ProjectInfo projInfo = (ProjectInfo)htProjectsAndNames[nodeName];
            
            Identity[] groups = IsProjectSite ? tfsSecurityService.ListApplicationGroups(projInfo.Uri) : GetServerIdentities();

            Hashtable htUserAndRoles = new Hashtable();

            foreach (Identity TFSRole in groups)
            {
                Identity TFSRoleGroup = tfsSecurityService.ReadIdentity(SearchFactor.Sid, TFSRole.Sid, QueryMembership.Direct);
                string[] MemberSids = TFSRoleGroup.Members;

                foreach (string MemberSid in MemberSids)
                {
                    Identity userIdentity = tfsSecurityService.ReadIdentityFromSource(SearchFactor.Sid, MemberSid);
                    string userName = string.Empty;
                    if (string.IsNullOrEmpty(userIdentity.AccountName))
                    {
                        System.Diagnostics.Debug.Assert(string.IsNullOrEmpty(userIdentity.AccountName), "userIdentity.AccountName is null");
                        if (userIdentity.Domain.Contains("vstfs:///Classification") || string.IsNullOrEmpty(userIdentity.Domain))
                        {
                            continue;
                        }
                        else
                        {
                            userName = userIdentity.Domain + "\\" + userIdentity.DisplayName;
                        }
                    }
                    else
                    {
                        userName = userIdentity.Domain + "\\" + userIdentity.AccountName;
                    }
                    string displayName = userIdentity.DisplayName;
                    TfsUser tUser;

                    if (!htUserAndRoles.ContainsKey(userName))
                    {
                        tUser = new TfsUser(userName);
                    }
                    else
                        tUser = (TfsUser)htUserAndRoles[userName];

                    tUser.DisplayName = displayName;
                    tUser.AddRole(TFSRoleGroup.DisplayName, RoleType.TfsRole);


                    if (htUserAndRoles.ContainsKey(tUser.Name) == true)
                    {
                        /// Need to update the user with new roles.
                        /// So remove it now to avoid duplicate
                        /// key entry failure to the hashtable.
                        htUserAndRoles.Remove(tUser.Name);
                    }

                    htUserAndRoles.Add(tUser.Name, tUser);

                }
            }

            Collection<TfsUser> AllUsers = new Collection<TfsUser>();

            foreach (TfsUser tUser in htUserAndRoles.Values)
            {
                AllUsers.Add(tUser);
            }

            htUserAndRoles.Clear();

            return AllUsers;
        }

        /// <summary>
        ///   Get the identity of a given user.
        /// </summary>
        /// <param name="userName">Name of the user</param>
        /// <returns>The users's Identity object or null</returns>
        public Identity GetMemberIdentity(string userName)
        {
            Identity userIdentity = tfsSecurityService.ReadIdentity(SearchFactor.AccountName, userName, QueryMembership.Direct);
            return userIdentity;
        }


        /// <summary>
        ///   Get the TFS Data Tier Host name
        /// </summary>
        /// <returns>TFS Data Tier Host Name</returns>
        public string DataTierHostName
        {
            get
            {
                // string tfsdatathostname = null;



                return tfsDataHostName;
            }
        }

        public System.Uri ReportServiceUrl
        {
            get { return tfsReportsServiceUrl; }
        }

        public System.Uri BaseSiteUrl
        {
            get { return tfsBaseSiteUrl; }
        }

        public System.Uri AdminServiceUrl
        {
          get { return tfsAdminServiceUrl; }
        }

        private void GetHostNames()
        {
            RegistrationEntry[] entries = tfsRegistrationService.GetRegistrationEntries(String.Empty);

            // TODO: During productizing move this to a generic wrapper and move the type names to constants.
            foreach (RegistrationEntry entry in entries)
            {
                if (entry.Type == "vstfs" && entry.Databases.Length > 0)
                {
                   tfsDataHostName = entry.Databases[0].SQLServerName;
                }
                else if (entry.Type == "Reports")
                {
                    // Get the ReportsService
                    foreach (ServiceInterface si in entry.ServiceInterfaces)
                    {
                        if (si.Name == "ReportsService")
                        {
                            tfsReportsServiceUrl = new System.Uri(si.Url);
                            break;
                        }
                    }
                }
                else if (entry.Type == "Wss")
                {
                  // Get the BaseSiteUrl and WssAdminService
                  foreach (ServiceInterface si in entry.ServiceInterfaces)
                  {
                    if (si.Name == "BaseSiteUrl")
                    {
                      tfsBaseSiteUrl = new System.Uri(si.Url);
                    }
                    if (si.Name == "WssAdminService")
                    {
                      tfsAdminServiceUrl = new System.Uri(si.Url);
                    }
                  }
                }
            }
        }


 
        /// <summary>
        ///   Get all the application roles from TFS.
        /// </summary>
        /// <param name="nodeName">Name of the project</param>
        /// <returns>ReadOnlyCollection of Role names</returns>
        public ReadOnlyCollection<string> GetProjectApplicationGroups(string nodeName)
        {
            Collection<string> TFSRoleNames = new Collection<string>();

            ProjectInfo projInfo = (ProjectInfo)htProjectsAndNames[nodeName];

            Identity[] groups = IsProjectSite ? tfsSecurityService.ListApplicationGroups(projInfo.Uri) : GetServerIdentities();

            foreach (Identity appGroup in groups)
            {


                if (appGroup.Type == IdentityType.ApplicationGroup)
                {
                    TFSRoleNames.Add(appGroup.DisplayName);
                }
            }

            ReadOnlyCollection<string> TFSRoles = new ReadOnlyCollection<string>(TFSRoleNames);
            return TFSRoles;
        }

        /// <summary>
        ///   Add a user with given TFS role to specified Team Project
        /// </summary>
        /// <param name="userName">User Name</param>
        /// <param name="role">Role Name</param>
        /// <param name="nodeName">Project Name</param>
        public void AddUserToRole(string userName, string role, string nodeName)
        {
            Identity newMember = tfsSecurityService.ReadIdentityFromSource(SearchFactor.AccountName, userName);

            if (newMember == null)
            {
                InvalidTfsUserException iue = new InvalidTfsUserException(TFSResource.TFSInvalidUserErrorMsg, appTierHost);
                iue.User = userName;
                throw iue;
            }

            foreach (string rol in role.Split(';'))
            {
                Identity Role = GetRoleIdentity(rol, nodeName);

                try
                {
                    tfsSecurityService.AddMemberToApplicationGroup(Role.Sid, newMember.Sid);
                }
                catch (Microsoft.TeamFoundation.Server.GroupSecuritySubsystemException)
                {
                    /// Member already exist. Ignore it.
                }
            }

        }

        /// <summary>
        ///    Check if the user exist on the TFS server.
        /// </summary>
        /// <param name="userName">Domain Name of the user</param>
        /// <returns>If the user exist on TFS it will return true else false</returns>
        public bool IsUserExist(string userName)
        {
            if (String.IsNullOrEmpty(userName) == true)
                throw new ArgumentNullException(TFSResource.strUserName);

            if (tfsSecurityService == null)
                throw new InvalidTfsConnectionException(TFSResource.TFSNotConnectedErrorMsg);

            Identity tUser = tfsSecurityService.ReadIdentity(SearchFactor.AccountName, userName, QueryMembership.Direct);

            if (tUser == null)
                return false;
            else
                return true;
        }

        /// <summary>
        ///   Remove the User from TFS server
        /// </summary>
        /// <param name="userName">User Name</param>
        /// <param name="nodeName">Project Name</param>
        public void RemoveUser(string userName, string nodeName)
        {
            ProjectInfo projInfo = null;
            if (IsProjectSite)
            {
                projInfo = (ProjectInfo)htProjectsAndNames[nodeName];
                if (projInfo == null)
                    return;
            }

            Identity tUser = tfsSecurityService.ReadIdentity(SearchFactor.AccountName, userName, QueryMembership.Direct);

            if (tUser == null)
            {
                InvalidTfsUserException iue = new InvalidTfsUserException(TFSResource.TFSInvalidUserErrorMsg, appTierHost);
                iue.User = userName;
                throw iue;
            }

            Identity[] groups = IsProjectSite ? tfsSecurityService.ListApplicationGroups(projInfo.Uri) : GetServerIdentities();
            foreach (Identity Role in groups)
            {
                Identity TFSRoleGroup = tfsSecurityService.ReadIdentity(SearchFactor.Sid, Role.Sid, QueryMembership.Direct);
                string[] MemberSids = TFSRoleGroup.Members;

                Collection<string> memberSidCollection = new Collection<string>(MemberSids);
                if (memberSidCollection.Contains(tUser.Sid))
                    tfsSecurityService.RemoveMemberFromApplicationGroup(Role.Sid, tUser.Sid);
            }
        }

        /// <summary>
        ///    Get the TFS Role Identity for the given rolename and project 
        /// </summary>
        /// <param name="roleName">Name of the role</param>
        /// <param name="nodeName">Name of the project</param>
        /// <returns>Identity object</returns>
        private Identity GetRoleIdentity(string roleName, string nodeName)
        {
            ProjectInfo projInfo = (ProjectInfo)htProjectsAndNames[nodeName];
            Identity[] groups = IsProjectSite ? tfsSecurityService.ListApplicationGroups(projInfo.Uri) : GetServerIdentities();
            Identity Role = null;



            foreach (Identity TFSRole in groups)
            {
                Identity TFSRoleGroup = tfsSecurityService.ReadIdentity(SearchFactor.Sid, TFSRole.Sid, QueryMembership.Direct);
                if (String.Compare(TFSRoleGroup.DisplayName, roleName, StringComparison.CurrentCultureIgnoreCase) == 0)
                {
                    Role = TFSRole;
                    break;
                }
            }

            if (Role == null)
            {
                InvalidTfsRoleException tre = new InvalidTfsRoleException(TFSResource.TFSInvalidRoleErrorMsg, appTierHost);
                tre.TeamProject = nodeName;
                tre.Role = roleName;
                throw tre;
            }

            return Role;
        }
        /// <summary>
        /// Retrieve the list of tfs roles on the server
        /// </summary>
        /// <returns></returns>
        private Identity[] GetServerIdentities()
        {
            Identity[] groups = new Identity[2];
            
            //Team Foundation Administrators
            groups[0] = tfsSecurityService.ReadIdentity(SearchFactor.AdministrativeApplicationGroup, null, QueryMembership.None);
            //Service Accounts
            groups[1] = tfsSecurityService.ReadIdentity(SearchFactor.ServiceApplicationGroup, null, QueryMembership.None);
            return groups;

        }
    }
}
